﻿using System;
using System.Linq;
using System.Text;
using System.Windows;
using System.Collections.Generic;
using System.Collections;
using System.Drawing;
using PixentrationEngine;
using System.Threading;
using System.Windows.Threading;
using System.Windows.Controls;
using System.IO;
using WMPLib;
using System.Reflection;
using System.Timers;
using System.Windows.Documents;
using System.Diagnostics;


namespace Pixentration
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

/************************************* Constants and Class Wide variables **********************/
       
        /// <summary>
        /// list to store card images  
        /// </summary>
        List<System.Drawing.Image>imgList;
        /// <summary>
        /// temp cards to test matches
        /// </summary>
        Card match1, match2;
        /// <summary>
        /// card position holders
        /// </summary>
        int pos1, pos2;
        /// <summary>
        /// game dimension variable
        /// </summary>
        int dimension;
        /// <summary>
        /// final score values
        /// </summary>
        int currentScore, bonus;
        /// <summary>
        /// current listed state of the game
        /// </summary>
        String gameState;
        /// <summary>
        /// running instance of the game engine
        /// </summary>
        PixentrationGame game;
        /// <summary>
        /// scorecard list to store high scores
        /// </summary>
        List<ScoreEntry> scoreCard = new List<ScoreEntry>();
        /// <summary>
        /// Windows Media Player Instance
        /// </summary>
        WMPLib.WindowsMediaPlayer WMP;
        /// <summary>
        /// path to in game music
        /// </summary>
        string Musicpath;
        /// <summary>
        /// flag for whether a game is in session
        /// </summary>
        Boolean gameOn;
        /// <summary>
        /// timer to initiate shuffle
        /// </summary>
        System.Timers.Timer shuffleTimer;
        /// <summary>
        /// list to keep track of card order
        /// </summary>
        List<int> cardOrder;
        /// <summary>
        /// sentinel value for shuffle functions
        /// </summary>
        int intervalTracker = 0;
        
        
        
       ///Game settings and Constants///      
        PixGameSettings settings;
        /// <summary>
        /// image size
        /// </summary>
        System.Drawing.Size imgSize;
        /// <summary>
        /// number of cards
        /// </summary>
        const int numCards = 36;
        /// <summary>
        /// game time
        /// </summary>
        long gameTime;
        /// <summary>
        /// user supplied images path
        /// </summary>
        String url = null;
        /// <summary>
        /// number of times to shuffle 
        /// </summary>
        int shuffle;
        /// <summary>
        /// file name for in game music
        /// </summary>
        const string MUSIC_FILE_NAME = "PixMusic.mp3";

        
/****************************************** Game initialization *********************************/

        /// <summary>
        /// Main application initialization
        /// </summary>
        /// <remarks> <para>requirements 3.3, 4.2.3</para>
        /// <para> Along with the basic application initialization we
        /// also attach the card's event timers and the timer, score and game state timers
        /// this makes for more initial overhead but it also allows for faster game 
        /// initialization since they are always attached once the game begins.</para>
        /// </remarks>
        public MainWindow()
        {
            InitializeComponent();
            stockImages.IsChecked = true;
            EasyButton.IsChecked = true;
            getRegistry();
            setDimensions();            
            ParentWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen;
            game = new PixentrationGame();
            loadScoreBoard();
            prepMusic();

            ///attach timers
            game.tick += new GameTimingEventHandler(TimingEventFired);
            //attach score
            game.scoreChanged += new ScoreChangedHandler(game_scoreChanged);
            //attach game state
            game.stateChanged += new GameStateChangedHandler(game_stateChanged);

            //attach card handlers
            cardHandlers();            
        }

        /// <summary>
        /// set the dimensions for the game at startup
        /// </summary>
        /// <remarks> <para>requirements 5.6, 5.6.1, 5.6.2 </para>
        /// <para>Certain aspects such as the overall dimension of the 
        /// board have to be set at initialization.  This is done so that
        /// we can account for multiple screen resolutions</para>
        /// </remarks>
        private void setDimensions()
        {
            
            dimension = (int)System.Windows.SystemParameters.PrimaryScreenHeight;
            ParentWindow.Height = (dimension - 100);
            ParentWindow.Width = (dimension - 100);
            
        }

        ~MainWindow()
        {
            File.Delete(Musicpath);

        }

        /// <summary>
        /// Initializes the Windows Media Player instance and starts music.
        /// </summary>
        private void prepMusic()
        {
            // Load the music file from a resource.
            // Save it to a temporary file in the common application data folder (generally "C:\ProgramData\Pixentration").
            Musicpath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Pixentration\\" + MUSIC_FILE_NAME;
            Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Pixentration.Resources.Music." + MUSIC_FILE_NAME);
            using (Stream output = new FileStream(Musicpath, FileMode.Create))
            {
                byte[] buffer = new byte[32 * 1024];
                int read;

                while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    output.Write(buffer, 0, read);
                }
            }
            
            // Create and start the music player.
            WMP = new WindowsMediaPlayer();
            WMP.URL = Musicpath;

            WMP.settings.setMode("loop", true);
            Vol.Value = 5;
            MusicOn.IsChecked = true;   
        }


        /// <summary>
        /// Load scores to scoreboard tab
        /// </summary>
        /// <remarks> This will be called to update the soreboard at game initialization as well
        /// as when a high score is achieved</remarks>
        private void loadScoreBoard()
        {
            scoreCard = game.GetScores();
            String name = "Name:" + '\n';
            String date = "Time:" + '\n';
            String score = "Score:" + '\n';

            if (scoreCard.Count > 0)
            {
                foreach (ScoreEntry aScore in scoreCard)
                {
                    name += aScore.Name + '\n';
                    date += aScore.Time + '\n';
                    score += aScore.Score.ToString() + '\n';

                }
            }

            nameGrid.Content = name;
            dateGrid.Content = date;
            scoreGrid.Content = score;
            
        }
/*************************************************** Game Setup *****************************/

        /// <summary>
        /// New Game Button
        /// used to initiate a new game
        /// will also make gameboard visible 
        /// and enable game tab
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <remarks> <para>requirements 1.1, 3.1, 1.1.1, 1.1.2, 3.2, 4.1, 6.1, 6.2.1, 6.2, 6.2.2, 6.2.3 </para>
        /// <para>The new game button is where the game variables are set and the board tab and interface are
        /// initialized.  This is also where the images are shuffled and loaded.</para>
        /// <para>The cards size is determined by the size of the board set from the inital dimension calculations.  
        /// The cards sizes are controlled by the size of the image requested from the game engine</para>
        /// </remarks>
        private void ButtonNewGameClick(object sender, RoutedEventArgs e)
        {
            gameOn = true;
            currentScore = 0;
            bonus = 0;
            ///enable lower grid for scoring and time
            lowerGrid.Opacity = 1;
            quitButton.IsEnabled = true;
            //allocated game time 
            
            if (EasyButton.IsChecked == true)
            {
                gameTime = 180;
                shuffle = 0;
            }
            else if (MediumButon.IsChecked == true)
            {
                gameTime = 180;
                shuffle = 90;
            }
            else if (HardButton.IsChecked == true)
            {
                gameTime = 180;
                shuffle = 60;
            }
            if (stockImages.IsChecked == false)
            {
                if (!userUrl.Equals(null) && (userUrl.Text.Length > 0))
                {
                    url = userUrl.Text;
                    setRegistry(url);
                }
                else
                {
                    url = null;
                }
            }
            else
            {
                url = null;
            }
                        
            //load game settings
            imgSize = new System.Drawing.Size(dimension / 10, dimension / 10);
            settings.ImageSize = imgSize;
            settings.BoardSize = numCards;
            settings.GameTime = gameTime;
            settings.URL = url;
            //initialize game
            game.Initialize(settings);
            
            ///make sure all cards are enabled and visible
            loadCards(true);
                
            //make game board visible
            GameTab.IsEnabled = true;
            GameTab.IsSelected = true;

            //make score and timer visible
            //needs to be done so there aren't residual times and scores showing.
            ScoreLabel.Content = "";
            TimeLeftLabel.Content = "";
            ScoreLabel.Opacity = 1;
            TimeLeftLabel.Opacity = 1;

            //start game
            game.Start();
        }

        /// <summary>
        /// load values
        /// </summary>
        /// <param name="newGame"> tells whether this is the 
        /// first game or not</param>
        /// <remarks> <para> this is a sub function of the new game 
        /// button.  This is the method responsible for loading the images and
        /// the card numbers.  The numbers are what is used to mark matched pairs.
        /// Also notice that the backs of the cards are loaded dynamically from
        /// resources.</para>
        /// </remarks>
        private void loadCards(Boolean newGame)
        {
            
            imgList = game.GetImages();

            ///list of card images on board
            Card[] cardList = {card1, card2, card3, card4, card5, card6, card7, card8, 
                                  card9, card10, card11, card12, card13, card14, card15, 
                              card16, card17, card18, card19, card20, card21, card22, card23,
                              card24, card25, card26, card27, card28, card29, card30, card31,
                              card32, card33, card34, card35, card36};

            
            for (int i = 0; i < imgList.Count; i++ )
            {
                if (newGame && !cardList[i].IsEnabled)
                {
                    cardList[i].IsEnabled = true;
                    cardList[i].Opacity = 1;
                    cardList[i].reload();
                    //cardList[i].reverse();
                    
                }

                cardList[i].cardBack = game.BackImage;
                cardList[i].cardFace = imgList[i];
                cardList[i].cardNumber = i;
                
            }

            foreach (Card temp in cardList)
            {
                temp.cardBack = game.BackImage;
            }
            
        }

        /// <summary>
        /// attaches the story loaded card delegate
        /// </summary>
        /// <remarks> <para>Attaches the handlers to fire when the storyboard is completed, initially
        /// the handlers were dynamically declared on each new game but now they are declared at the 
        /// initialization of the application to keep down on the game initialization overhead</para></remarks>
        private void cardHandlers()
        {
            Card[] cardList = {card1, card2, card3, card4, card5, card6, card7, card8, 
                                  card9, card10, card11, card12, card13, card14, card15, 
                              card16, card17, card18, card19, card20, card21, card22, card23,
                              card24, card25, card26, card27, card28, card29, card30, card31,
                              card32, card33, card34, card35, card36};

            for (int i = 0; i < cardList.Length; i++)
            {
                //cardList[i].showOver -= new Card.myDelegate(Story_Loaded);
                cardList[i].showOver +=new Card.myDelegate(Story_Loaded);

            }
            
        }
               


/**************************************************** Gameplay Methods ************************************/
        /// <summary>
        /// event that is fired when the storyboard loads
        /// </summary>
        /// <param name="sender"></param>
        /// <remarks> <para> requirements 7.2, 7.2.1, 7.2.2 </para>
        /// <para>when a card's animation finishes this checks to make sure that the card has not been
        /// clicked more than once and whether the first or second match slot is open.  If this is the second card
        /// a call to see if the cards are a match is made</para></remarks>
        private void Story_Loaded(object sender)
        {

            if (match1 == null)
            {
                match1 = (sender as Card);
                pos1 = match1.cardNumber;
                match1.IsEnabled = false;

            }
            else if ((match2 == null && match1 != null) && 
                    (match1.cardNumber != (sender as Card).cardNumber) && 
                    (-1 != (sender as Card).cardNumber))
            {
                match2 = (sender as Card);
                pos2 = match2.cardNumber;

                //TODO put in test match
                if (game.TestMatch(pos1, pos2))
                {
                    /// disable matched cards                    
                    match2.IsEnabled = false;
                    match1.Opacity = 0;
                    match2.Opacity = 0;
                    ///set tag value to -1
                    match1.cardNumber = -1;
                    match2.cardNumber = -1;
                    ///set match values to null
                    match1 = null;
                    match2 = null;
                }
                else
                {
                    match1.IsEnabled = true;
                    match1.reverse();
                    match2.reverse();
                    match1 = null;
                    match2 = null;
                }
            }
        }
                
        /// <summary>
        /// Shuffles the cards after gameplay has started
        /// given an increment to shuffle at
        /// </summary>
        /// <remarks> <para>checks for all remaining cards before determining the 
        /// locations to shuffle at uses timer event to update graphics and show shuffle</para>
        /// </remarks>
        public void shuffleIt()
        {
            game.Pause();
            int timerInterval;
            boardLock(true);
                        
             Card[] cardList = {card1, card2, card3, card4, card5, card6, card7, card8, 
                                  card9, card10, card11, card12, card13, card14, card15, 
                              card16, card17, card18, card19, card20, card21, card22, card23,
                              card24, card25, card26, card27, card28, card29, card30, card31,
                              card32, card33, card34, card35, card36};

            cardOrder = new List<int>();

            for(int j = 0; j < cardList.Length; j++)
            {
                if(cardList[j].cardNumber > -1)
                {
                    cardOrder.Add(cardList[j].cardNumber);
                }
            }

            timerInterval = 5000 / cardOrder.Count;
            shuffleTimer = new System.Timers.Timer(timerInterval);
            shuffleTimer.Elapsed += new ElapsedEventHandler(shuffleTimer_Elapsed);
            shuffleTimer.Start();
                    
        }

        /// <summary>
        /// Game clean up and possible high score assignment
        /// </summary>
        /// <param name="highScore"> tells whether the score is the high score</param>
        /// <remarks> <para>at the end of the game cleans up the board and fires off the 
        /// end of game dialog stating either game over or high score.</para>
        /// </remarks>
        private void endGame(Boolean highScore)
        {
            gameOn = false;
            bonus = game.CurrentScore - currentScore;
            

            Thread t = new Thread(
                     new ThreadStart(
                     delegate
                     {
                         Dispatcher.BeginInvoke(
                         DispatcherPriority.Normal,
                         new Action(
                             delegate
                             {
                                 GameTab.IsEnabled = false;
                                 OptionsTab.IsSelected = true;
                                 //GameBoard.IsEnabled = false;
                                 ///disable lower grid for scoring and time
                                 lowerGrid.Opacity = 0;
                                 quitButton.IsEnabled = false;
                             }
                         ));
                     }
                 ));
            t.Start();


            Thread t2 = new Thread(
                    new ThreadStart(
                    delegate
                    {
                        Dispatcher.BeginInvoke(
                        DispatcherPriority.Normal,
                        new Action(
                            delegate
                            {
                                EndGame dialog = new EndGame();
                                dialog.isHighScore(highScore);
                                if (game.CurrentScore > 0)
                                {
                                    dialog.setFields(currentScore, bonus, game.CurrentScore);
                                }
                                else
                                {
                                    dialog.setFields(0, 0, 0);
                                }
                                dialog.WindowStartupLocation = WindowStartupLocation.CenterScreen;
                                dialog.ShowDialog();
                                if (highScore)
                                {
                                    game.SetHighScoreName(dialog.getInitials());
                                    loadScoreBoard();
                                    ScoreBoardTab.IsSelected = true;
                                }

                            }
                        ));
                    }
                ));
            t2.Start();
            
        }

/****************************************** Event Triggers ***************************************************/

        /// <summary>
        /// Timer Fire event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        /// <remarks><para> requirements 5.5 </para>
        /// For the timer event to be visible on the board when it is fired
        /// a  new thread has to be dispatched to the UI, otherwise an exception is thrown
        /// because the current thread attempting to update the timer visual doesn't own the
        /// thread associated with the UI and there are a large number of attempted updates</remarks>
        void TimingEventFired(object sender, TimingEventArgs args)
        {            

            Thread t = new Thread(new ThreadStart(
            delegate
            {
                Dispatcher.Invoke(DispatcherPriority.Normal, new Action<Label>(SetValue), TimeLeftLabel);
            }
            ));
            t.Start();
            gameTime--;

        }

        /// <summary>
        /// Set the value for the timer event
        /// </summary>
        /// <param name="txt"> the label value associated with the timer visual</param>
        /// <remarks> <para>This is the helper method within the new thread created in the above event.
        /// The current value of the timer is retrieved and then a few simple calcuations are done to 
        /// break the time down into minutes and seconds</para>
        /// </remarks>
        private void SetValue(Label txt)
        {
            int minutes, seconds;
            minutes = (int)gameTime / 60;
            seconds = (int)gameTime % 60;
            String time;
            if (seconds < 10)
            {
                time = minutes + ":0" + seconds;
            }
            else
            {
                time = minutes + ":" + seconds;
            }

            txt.Content = time;

            Boolean isStarting = false;

            if (gameTime > 170)
            {
                isStarting = true;
            }
            else
            {
                isStarting = false;
            }
                        
            if (shuffle != 0  && gameTime % shuffle == 0 && !isStarting)
            {
                shuffleIt();
            }

            
        }
         


        /// <summary>
        /// Updates the score as it is changed by the game engine
        /// </summary>
        /// <remarks> <para>requirements 8.1.1, 8.1.2, 8.1.3, 8.1.6, 8.2.1, 8.1.7</para>
        ///  <para> Notice this does not require a new thread because of the limited and 
        ///  heavily spaced out events that fire on a match.  Which results in no thread ownership
        ///  issues</para></remarks>
        void game_scoreChanged (object sender, ScoreEventArgs args)
        {
            if ("Match".Equals(args.type.ToString()) || "Mismatch".Equals(args.type.ToString()))
            {
                currentScore = args.newScore;
            }
            
            ScoreLabel.Content = args.newScore;
            
        }

        /// <summary>
        /// changes the game state of the engine depending on event fired 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        /// <remarks> <para> The gamestate is kept in a globa variable there are multiple possible states
        /// accounted for even though the only ones we really care for are start and paused which are used
        /// in the navigation event to determine whether or not we need to pause the game</para></remarks>
        void game_stateChanged(object sender, StateEventArgs args) {

            String temp = args.state.ToString();

            switch (temp) {
                case "Paused":
                    game.Pause();
                    gameState = "pause";
                    break;
                case "Stopped":
                    //game.Stop();
                    gameState = "blah";
                    break;
                case "Ended":
                    endGame(false);
                    gameState = "blah";
                    break;
                case "EndedWithHighScore":
                    endGame(true);
                    gameState = "blah";
                    break;
                case "Initialized":
                    gameState = "start";
                    break;
                case "Start":
                    game.Start();
                    gameState = "start";
                    break;
                default:                    
                    break;                    
            }


        }

        /// <summary>
        /// fired when the quit game button is clicked
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <remarks> <para> requirements 1.2, 1.2.1, 1.2.2, 1.2.3, 3.2 </para>
        /// <para>Secondary way to end the game not tied to the
        /// endGame event.  Navigates away from the game board and 
        /// disables both the board and the tab so you can't navigate back.
        /// The only way to access the game board is through the new game
        /// button</para>
        /// </remarks>
        private void QuitButton_Click(object sender, RoutedEventArgs e)
        {
            gameOn = false;
            
            if (game.CurrentState == PixGameState.Running ||
                game.CurrentState == PixGameState.Paused)
            {
                game.Stop();
            }

            match1 = null;
            match2 = null;
            OptionsTab.IsSelected = true;
            GameTab.IsEnabled = false;
            ScoreLabel.Opacity = 0;
            TimeLeftLabel.Opacity = 0;
            lowerGrid.Opacity = 0;
            quitButton.IsEnabled = false;

        }


        /// <summary>
        /// notifies the game when the view is changed from one tab to the next
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <remarks> <para> requirements 1.5 </para>
        /// <para> Used to notify the game when you navigate to or away from the
        /// board so the game can be paused or restarted as necessary</para></remarks>
        private void View_Changed(object sender, RoutedEventArgs e)
        {
            TabItem temp = sender as TabItem;
            String sTemp = temp.Header.ToString();

            if (gameOn)
            {
                if (!sTemp.Equals("Game"))
                {
                    game.Pause();
                }
                else 
                {
                    game.Start();
                }
            }
        
        }


        /// <summary>
        /// Event that provides for mid game shuffle and animation
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="E"></param>
        /// <remarks> <para>this has to be a separate thread so that the ui will update
        /// otherwise the program will refuse the update as the cards are owned 
        /// by the main ui thread </para></remarks>
        private void shuffleTimer_Elapsed(object sender, EventArgs E)
        {
            
            //randomizer 
            Random rand = new Random();
                        
            Card[] cardList = {card1, card2, card3, card4, card5, card6, card7, card8, 
                                  card9, card10, card11, card12, card13, card14, card15, 
                              card16, card17, card18, card19, card20, card21, card22, card23,
                              card24, card25, card26, card27, card28, card29, card30, card31,
                              card32, card33, card34, card35, card36};
            Thread t = new Thread(
                     new ThreadStart(
                     delegate
                     {
                         Dispatcher.BeginInvoke(
                         DispatcherPriority.Normal,
                         new Action(
                             delegate
                             {

                                 foreach (Card aCard in cardList)
                                 {
                                     if (aCard.Opacity == 0 && aCard.cardNumber >= 0)
                                     {

                                         aCard.Opacity = 1;

                                     }
                                 }

                                 if (intervalTracker > cardOrder.Count)
                                 {
                                     shuffleTimer.Stop();
                                     shuffleTimer.Dispose();
                                     intervalTracker = 0;
                                     game.Start();
                                     boardLock(false);
                                     return;
                                 }
                                 else
                                 {
                                     intervalTracker++;
                                 }
                                
                                 // Generate two indices to swap at random.
                                 int first = rand.Next() % cardOrder.Count;
                                 int second = rand.Next() % cardOrder.Count;
                                 while (!cardOrder.Contains(first))
                                 {
                                     first = rand.Next() % cardOrder.Count;
                                 }
                                 while (!cardOrder.Contains(second) && second != first)
                                 {
                                     second = rand.Next() % cardOrder.Count;
                                 }
                                 //Swap cards at those locations
                                 Card temp = new Card();
                                 temp.setCardFace(cardList[cardOrder[first]].getCardFace());
                                 temp.cardNumber = cardList[cardOrder[first]].cardNumber;
                                 cardList[cardOrder[first]].setCardFace(cardList[cardOrder[second]].getCardFace());
                                 cardList[cardOrder[first]].cardNumber = cardList[cardOrder[second]].cardNumber;
                                 cardList[cardOrder[second]].setCardFace(temp.getCardFace());
                                 cardList[cardOrder[second]].cardNumber = temp.cardNumber;
                                 cardList[cardOrder[first]].Opacity = 0;
                                 cardList[cardOrder[second]].Opacity = 0;

                             }
                         ));
                     }
                 ));
            t.Start();
                                             
        }

        /// <summary>
        /// lock the gameboard for shuffling
        /// </summary>
        /// <remarks> <para> The board is locked before the shuffle begins.  This
        /// is done because we don't want the user to be able to make selections while the
        /// shuffle is going on to avoid unneccessary conflicts.</para>
        /// </remarks>
        private void boardLock(Boolean shouldLock)
        {
            Thread t = new Thread(
                     new ThreadStart(
                     delegate
                     {
                         Dispatcher.BeginInvoke(
                         DispatcherPriority.Normal,
                         new Action(
                             delegate
                             {
                                 if (shouldLock)
                                 {
                                     GameBoard.IsEnabled = false;
                                 }
                                 else
                                 {
                                     GameBoard.IsEnabled = true;
                                 }
                             }
                         ));
                     }
                 ));
            t.Start();
        }



/************************************************** Miscellaneous Controls ******************************************/

        /// <summary>
        /// Help button Event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <remarks><para> requirements 2.1 </para>
        /// <para> This will launch the User's Manual PDF that is stored in the
        /// home directory of the application</para></remarks>
        private void HelpButton_Click(object sender, RoutedEventArgs e)
        {
            String exePath = System.IO.Path.GetDirectoryName(
                System.Reflection.Assembly.GetExecutingAssembly().Location);
            String fileName = exePath += @"\Pixentration User's Guide.pdf"; 
            System.Diagnostics.Process process = new System.Diagnostics.Process(); 
            process.StartInfo.FileName = fileName; process.Start(); 
            process.WaitForExit();
        }
         
        /// <summary>
        /// Browse button event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <remarks> <para>requirements  4.2, 4.2.2, 4.2.2.1</para>
        /// <para> This is grayed out by default and only enabled when the user
        /// chooses to unselect the use stock images box.  Opens a standard windows
        /// folder browse dialog</para></remarks>
        private void Browse_Click_1(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.FolderBrowserDialog folderChooser = new System.Windows.Forms.FolderBrowserDialog();
            System.Windows.Forms.DialogResult result = folderChooser.ShowDialog();
            if (result == System.Windows.Forms.DialogResult.OK)
            {
                userUrl.Text = folderChooser.SelectedPath;
            }
        }

        /// <summary>
        /// retrieves the file path from registry
        /// </summary>
        /// <remarks> <para> Retrieves the path that the user provides for their own images
        /// this populates the browse text box by default on game load so the user doens't
        /// have to navigate to their images at the start of every game</para>
        /// </remarks>
        private void getRegistry()
        {
            Microsoft.Win32.RegistryKey key;
            key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey("Pixentration");
            if (key.GetValue("path") != null)
            {
                userUrl.Text = key.GetValue("path").ToString();
            }
            
        }

        /// <summary>
        /// sets the file patch to the registry
        /// </summary>
        /// <param name="path"> file path</param>
        /// <remarks> <para>This sets the path that the user provides for their own images
        /// which is stored in the registry in it's out key under the current user section</para></remarks>
        private void setRegistry(String path)
        {
            Microsoft.Win32.RegistryKey key;
            key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey("Pixentration");
            if (key.GetValue("path") == null)
            {
                key.SetValue("path", path);
                key.Close();
            }
        }

        /// <summary>
        /// Music on
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <remarks><para> Turns the music on when the radial is clicked</para></remarks>
        private void RadioButton_Checked(object sender, RoutedEventArgs e)
        {
            WMP.controls.play();

        }

        /// <summary>
        /// Music volume
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <remarks> <para>requirements 4.3, 4.3.1 </para>
        /// <para> Slider to adjust the music volume</para>
        /// </remarks>
        private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            WMP.settings.volume = (int)Vol.Value * 10;

        }

        /// <summary>
        /// Music off
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <remarks><para> Turns the music on when the radial is clicked</para></remarks>
        private void RadioButton_Checked_1(object sender, RoutedEventArgs e)
        {
            WMP.controls.pause();
        }

        /// <summary>
        /// event to enable and disable the browse button and corresponding text box
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <remarks> <para>requirements 4.2.3.1 </para>
        /// <para> In the options screen if the user checks the use stock images
        /// we disable the text box and browse buttons.  Also by default the use stock images
        /// is checked at startup </para></remarks>
        private void stockImages_Checked(object sender, RoutedEventArgs e)
        {
            if (true.Equals(stockImages.IsChecked))
            {
                userUrl.IsEnabled = false;
                Browse.IsEnabled = false; 
            }
            else
            {
                userUrl.IsEnabled = true;
                Browse.IsEnabled = true; 
            }
        }


        /// <summary>
        /// Hyperlink event neccessary to open a URL
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <remarks><para>requirements 2.3.3.1 </para>
        /// <para> This event is required to fire the two hyperlinks located
        /// on the about tab.  They have both been coded in to the XAML on the page but
        /// since this is a WPF application and not a .NET application we cannot
        /// fire them directly from the Xaml code.</para></remarks>
        private void Hyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e)
        {
            Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
            e.Handled = true;
        }


      
    }
}
